export default class Adsorb {
  constructor({ positionId, adsorbPadding = 10, lineOffset = 5 }) {
    this.hLine = []
    this.vLine = []
    // 除活动元素外所有元素的信息
    this.allElementData = []
    this.activeId = 0
    this.activeElementData = {}
    this.activeElementLine = []
    // 代表父元素ID
    this.positionId = positionId
    // 父元素的定位数据
    this.positionData = {}
    // 代表的吸附距离
    this.adsorbPadding = adsorbPadding
    // 线的长度上下左右都加上lineOffset
    this.lineOffset = lineOffset
    // 寻找到的需要画出来的线
    this.canvasLine = {}
    this.startPoint = {
      x: 0,
      y: 0
    }
    // 运动方向 l r t b
    this.direction = ''
    // 用于吸附操作
    this.adsorbPostion = {
      left: 0,
      top: 0
    }
    this.getPositionData()
  }

  // 初始化数据
  init({ activeId, elementClassName }) {
    this.clearLine()
    this.setActiveId(activeId)
    const elements = document.getElementsByClassName(elementClassName)
    this.setAllElementData(elements)
    this.setLine()
    this.setMoveLines()
    this.startPoint = {
      x: this.activeElementData.x,
      y: this.activeElementData.y
    }
    this.adsorbPostion = {
      left: 0,
      top: 0
    }
  }

  // 设置活动元素id
  setActiveId(id) {
    this.activeId = id
  }

  /**
   * line {
   *   type: '类型',
   *   pos: '定位', h => 水平 pos 定位点是top，center，bottom； v => 垂直 pos 定位点是left、center、right
   *   start: '起点',
   *   end: '结束点,
   * }
   * */
  // 添加水平线
  addHLine(line) {
    this.hLine.push(line)
    this.hLine = this.hLine.sort((pre, next) => pre.pos - next.pos)
  }

  // 添加垂直线
  addVLine(line) {
    this.vLine.push(line)
    this.vLine = this.vLine.sort((pre, next) => pre.pos - next.pos)
  }

  // 删除水平线
  removeHLine(line) {
    console.log(line)
  }

  // 删除垂直线
  removeVLine(line) {
    console.log(line)
  }

  // 清空线条
  clearLine() {
    this.hLine = []
    this.vLine = []
  }

  // 获取定位点数据
  getPositionData() {
    const element = document.getElementById(this.positionId)
    this.positionData = element.getBoundingClientRect()
  }

  // 设置拖出来的线
  setMoveLines() {
    const { left, top, right, bottom, width, height } = this.positionData
    this.addHLine({
      type: 'h',
      pos: top + height / 2,
      start: left + this.lineOffset,
      end: right - this.lineOffset
    })
    this.addVLine({
      type: 'v',
      pos: left + width / 2,
      start: top,
      end: bottom
    })
  }

  // 获取所有元素的数据
  setAllElementData(elements) {
    this.allElementData = []
    const len = elements.length
    for (let i = 0; i < len; i++) {
      const element = elements[i]
      const key = parseInt(element.dataset.key)
      if (this.activeId !== key) {
        const rect = element.getBoundingClientRect()
        this.allElementData.push(rect)
      } else {
        this.setActiveElementData(element)
      }
    }
  }

  // 设置线条数据
  setLine() {
    this.allElementData.forEach(data => {
      const top = data.top
      const topM = top + data.height / 2
      const bottom = data.bottom
      const left = data.left
      const leftM = left + data.width / 2
      const right = data.right
      const line = {
        v: [
          { type: 'vl', pos: left, start: top, end: bottom },
          { type: 'vm', pos: leftM, start: top, end: bottom },
          { type: 'vr', pos: right, start: top, end: bottom }
        ],
        h: [
          { type: 'ht', pos: top, start: left, end: right },
          { type: 'hm', pos: topM, start: left, end: right },
          { type: 'hb', pos: bottom, start: left, end: right }
        ]
      }
      for (let i = 0; i < 3; i++) {
        this.addHLine(line.h[i])
        this.addVLine(line.v[i])
      }
    })
  }

  // 设置活动元素的线
  setActiveElementLine() {
    const { left, top, right, bottom, width, height } = this.activeElementData
    const topM = top + height / 2
    const leftM = left + width / 2
    this.activeElementLine = [
      { type: 'ht', pos: top, start: left, end: right },
      { type: 'hm', pos: topM, start: left, end: right },
      { type: 'hb', pos: bottom, start: left, end: right },
      { type: 'vl', pos: left, start: top, end: bottom },
      { type: 'vm', pos: leftM, start: top, end: bottom },
      { type: 'vr', pos: right, start: top, end: bottom }
    ]
  }

  // 获取移动元素的数据
  setActiveElementData(element) {
    if (element) {
      this.activeElementData = element.getBoundingClientRect()
      this.setActiveElementLine()
      this.getMoveDirection({ x: this.activeElementData.x, y: this.activeElementData.y })
    }
  }

  // 判断运动方向
  getMoveDirection({ x, y }) {
    const offsetX = x - this.startPoint.x
    const offsetY = y - this.startPoint.y
    const arr = []
    if (Math.abs(offsetX) >= Math.abs(offsetY)) {
      if (offsetX > 0) {
        arr.push('r')
      }
      if (offsetX < 0) {
        arr.push('l')
      }
    } else {
      if (offsetY > 0) {
        arr.push('b')
      }
      if (offsetY < 0) {
        arr.push('t')
      }
    }
    if (offsetX !== 0 || offsetY !== 0) {
      this.direction = arr.join('')
    }
  }

  // 寻找一条或多条合适的线
  findLines() {
    const pos = {}
    this.activeElementLine.forEach(item => {
      pos[item.type] = item.pos
    })
    const newLines = {}
    this.activeElementLine.forEach(line => {
      const lineArr = /v/.test(line.type) ? this.vLine : this.hLine
      const data = this.findLine(line, lineArr, /v/.test(line.type)).filter(item => {
        if (/[lt]/.test(this.direction)) {
          return item.pos <= pos[line.type]
        }
        if (/[rb]/.test(this.direction)) {
          return item.pos >= pos[line.type]
        }
        return false
      })

      if (data.length > 0) {
        newLines[line.type] = data
      }
    })

    this.adsorbPostion = {
      left: 0,
      top: 0
    }
    const startArr = { l: [], r: [], t: [], b: [] }
    Object.keys(newLines).forEach(key => {
      if (/[lt]/.test(this.direction)) {
        const data = newLines[key].filter(item => {
          return item.pos <= pos[key]
        })
        const startKey = /l/.test(this.direction) ? 'l' : 't'
        if (data.length > 0) {
          startArr[startKey].push({ type: data[data.length - 1].type, value: data[data.length - 1].pos - pos[key] })
        }
      }
      if (/[rb]/.test(this.direction)) {
        const data = newLines[key].filter(item => {
          return item.pos >= pos[key]
        })
        const startKey = /r/.test(this.direction) ? 'r' : 'b'
        if (data.length > 0) {
          startArr[startKey].push({ type: data[data.length - 1].type, value: data[data.length - 1].pos - pos[key] })
        }
      }
    })
    Object.keys(startArr).forEach(key => {
      if (startArr[key].length > 0) {
        const min = Math.min(...startArr[key].map(item => item.value))
        if (/[lr]/.test(this.direction)) {
          this.adsorbPostion.left = min
        }
        if (/[tb]/.test(this.direction)) {
          this.adsorbPostion.top = min
        }
      }
    })

    this.startPoint = {
      x: this.activeElementData.x,
      y: this.activeElementData.y
    }
    this.canvasLine = newLines
  }

  // 通过二分法计算操作获取一条合适的线
  /* findLine(targetLine, lines, l = 0, r = 0, preLine = {}) {
    if (lines && lines.length > 0) {
      r = r === 0 ? lines.length - 1 : r
      if (l > r) {
        const x1 = Math.abs(lines[r].pos - targetLine.pos)
        const x2 = Math.abs(preLine.pos - targetLine.pos)
        return x1 < x2 ? lines[r] : preLine
      }
      if (l === r) {
        const x1 = Math.abs(lines[l].pos - targetLine.pos)
        const x2 = Math.abs(preLine.pos - targetLine.pos)
        return x1 < x2 ? lines[l] : preLine
      }
      if (r - l === 1) {
        const x1 = Math.abs(lines[l].pos - targetLine.pos)
        const x2 = Math.abs(lines[r].pos - targetLine.pos)
        let x3 = 10000
        if (preLine.pos) {
          x3 = Math.abs(preLine.pos - targetLine.pos)
        }
        if (x1 <= x2 && x1 <= x3) {
          return lines[l]
        }
        if (x2 <= x1 && x2 <= x3) {
          return lines[r]
        }
        if (x3 <= x1 && x3 <= x2) {
          return preLine
        }
      }
      if (r - l > 1) {
        const center = Math.ceil((r + l) / 2)
        if (targetLine.pos === lines[center].pos) {
          return lines[center]
        }
        if (targetLine.pos > lines[center].pos) {
          return this.findLine(targetLine, lines, center, r, lines[center])
        }
        if (targetLine.pos < lines[center].pos) {
          return this.findLine(targetLine, lines, l, center, lines[center])
        }
      }
    }
  }*/
  findLine(targetLine, lines, state) {
    const filterData = lines.filter(item => {
      if ((state && /[lr]/.test(this.direction)) || (!state && /[tb]/.test(this.direction))) {
        return Math.abs(item.pos - targetLine.pos) <= this.adsorbPadding
      }
      return Math.abs(item.pos - targetLine.pos) === 0
    })
    return filterData
  }

  getLines() {
    const keys = Object.keys(this.canvasLine)
    return keys.map(key => {
      const activeLine = this.activeElementLine.find(item => item.type === key)
      const start = Math.min(...this.canvasLine[key].map(item => item.start), activeLine.start) - this.lineOffset
      const end = Math.max(...this.canvasLine[key].map(item => item.end), activeLine.end) + this.lineOffset
      const state = /h/.test(key)
      return {
        type: state ? 'h' : 'v',
        width: state ? end - start : 1,
        height: state ? 1 : end - start,
        top: state ? activeLine.pos - this.positionData.y + this.adsorbPostion.top : start - this.positionData.y + this.adsorbPostion.top,
        left: state ? start - this.positionData.x + this.adsorbPostion.left : activeLine.pos - this.positionData.x + this.adsorbPostion.left
      }
    })
  }

  // 吸附后返回的target 元素的定位
  getPosition() {
    return {
      left: this.adsorbPostion.left,
      top: this.adsorbPostion.top
    }
  }
}

